package com.xs.gis.util;

import com.xs.gis.domain.geojson.*;
import org.apache.commons.lang3.StringUtils;
import org.gdal.ogr.*;
import org.gdal.osr.SpatialReference;
import org.geotools.referencing.CRS;
import org.json.simple.JSONObject;
import org.locationtech.jts.geom.Geometry;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author w
 * @Description TODO
 * @date 2023/8/17-9:49
 */
public class GisCommonUtils {

    /**
     * 判断是否是经纬度坐标系
     *
     * @param x
     * @param y
     * @return
     */
    public static boolean isGeographicCoordinate(double x, double y) {
        return (x >= -180.0 && x <= 180.0) && (y >= -90.0 && y <= 90.0);
    }

    //元数据和坐标轴单位：EPSG:XXXX
    //要准确地判断坐标系的类型，最好的方式是查看坐标系的元数据。您可以尝试从数据源中获取 EPSG 对应的坐标系元数据，例如坐标轴单位。经纬度坐标系通常使用度（degrees--deg）
    // 作为坐标轴单位，而投影坐标系可能使用米（meters--m）或其他单位。
    public static String detectCRSType(String epsgCode) {
        try {
            CoordinateReferenceSystem crs = CRS.decode(epsgCode);
            String xAxisUnit = crs.getCoordinateSystem().getAxis(0).getUnit().toString();
            String yAxisUnit = crs.getCoordinateSystem().getAxis(1).getUnit().toString();

            if ("deg".equalsIgnoreCase(xAxisUnit) && "deg".equalsIgnoreCase(yAxisUnit)) {
                return "Geographic";
            } else {
                return "Projected";
            }
        } catch (FactoryException e) {
            e.printStackTrace();
            return "Error";
        }
    }


    /**
     * 删除文件
     *
     * @param filePath
     */
    public static void deleteExistsFile(String filePath) {
        File file = new File(filePath);
        if (file.exists()) {
            if (file.isFile()) {
                file.delete();
            }
            if (file.isDirectory()) {
                File[] files = file.listFiles();
                for (File file1 : files) {
                    file1.delete();
                }
                file.delete();
            }
        }
    }


    /**
     * 初始化导出的几何类型
     *
     * @param geoFeature
     * @return
     */
    public static int initGeomType(GeoFeature geoFeature) {
        int geom_type = ogr.wkbPolygon;
        BaseGeometry geometry = geoFeature.getGeometry();
        String type = geometry.getType();

        switch (type) {
            case Geometry.TYPENAME_POINT:
                geom_type = ogr.wkbPoint;
                break;
            case Geometry.TYPENAME_LINESTRING:
                geom_type = ogr.wkbLineString;
                break;
            case Geometry.TYPENAME_LINEARRING:
                geom_type = ogr.wkbLinearRing;
                break;
            case Geometry.TYPENAME_POLYGON:
                geom_type = ogr.wkbPolygon;
                break;
            case Geometry.TYPENAME_MULTIPOINT:
                geom_type = ogr.wkbMultiPoint;
                break;
            case Geometry.TYPENAME_MULTILINESTRING:
                geom_type = ogr.wkbMultiLineString;
                break;
            case Geometry.TYPENAME_MULTIPOLYGON:
                geom_type = ogr.wkbMultiPolygon;
                break;
            case Geometry.TYPENAME_GEOMETRYCOLLECTION:
                geom_type = ogr.wkbGeometryCollection;
                break;
            default:
                geom_type = ogr.wkbUnknown;
        }
        return geom_type;

    }

    /**
     * 添加数据
     *
     * @param features 空间数据
     * @param gdbLayer 图层
     * @param epsgCode 参考系编码
     */
    public static void addGdbData( List<GeoFeature> features, Layer gdbLayer, String epsgCode) {
        addGdbData(features, gdbLayer, epsgCode, null);
    }

    /**
     * 添加数据
     *
     * @param features    空间数据
     * @param gdbLayer    图层
     * @param epsgCode    参考系编码
     * @param ignoreFiled 过滤字段
     */
    public static void addGdbData( List<GeoFeature> features, Layer gdbLayer, String epsgCode, String ignoreFiled) {
        features.stream().forEach(x -> {
            FeatureDefn oDefn = gdbLayer.GetLayerDefn();
            Feature oFeatureTriangle = new Feature(oDefn);
            Map<String, Object> properties = x.getProperties();
            properties.entrySet().stream().forEach(item -> {
                if (!String.valueOf(item).equalsIgnoreCase(ignoreFiled)) {
                    oFeatureTriangle.SetField(String.valueOf(item.toString()).toUpperCase(), String.valueOf(properties.get(item)));
                }
            });
            Geometry geometry = x.formatGeometry(Integer.valueOf(epsgCode));
            org.gdal.ogr.Geometry geometryNew = org.gdal.ogr.Geometry.CreateFromWkt(geometry.toString());
            oFeatureTriangle.SetGeometry(geometryNew);

            gdbLayer.CreateFeature(oFeatureTriangle);
            oFeatureTriangle.delete();
            oDefn.delete();
        });
    }

    /**
     * 创建图层
     *
     * @param feature       空间数据
     * @param dataSourceGDB 数据源
     * @param epsgCode      获得epsgCode
     * @return
     */
    public static Layer createLayer(GeoJsonFeature feature, DataSource dataSourceGDB, String epsgCode) {
        return createLayer(feature, dataSourceGDB, epsgCode, null);
    }


    /**
     * 创建图层
     *
     * @param feature       空间数据
     * @param dataSourceGDB 数据源
     * @param epsgCode      获得epsgCode
     * @param ignoreFiled   过滤字段
     * @return
     */

    public static Layer createLayer(GeoJsonFeature feature, DataSource dataSourceGDB, String epsgCode, String ignoreFiled) {

        SpatialReference sr = new SpatialReference();
        sr.ImportFromEPSG(Integer.valueOf(epsgCode));

        GeoFeature geoFeature = feature.getFeatures().get(0);
        int geomType = GisCommonUtils.initGeomType(geoFeature);
        Layer gdbLayer = dataSourceGDB.CreateLayer(feature.getLayerName(), sr, geomType, null);


        Map<String, Object> properties = geoFeature.getProperties();
        properties.forEach((k, v) -> {
            String key = String.valueOf(k);
            if (StringUtils.isBlank(ignoreFiled) || !key.toUpperCase().equalsIgnoreCase(ignoreFiled)) {
                // 创建字段
                if (v instanceof String) {
                    FieldDefn oFieldName = new FieldDefn(key.toUpperCase(), ogr.OFTString);
                    oFieldName.SetWidth(300);
                    gdbLayer.CreateField(oFieldName);
                } else if (v instanceof Integer) {
                    FieldDefn oFieldName = new FieldDefn(key.toUpperCase(), ogr.OFTInteger);
                    gdbLayer.CreateField(oFieldName);
                } else if (v instanceof Double) {
                    FieldDefn oFieldName = new FieldDefn(key.toUpperCase(), ogr.OFTReal);
                    gdbLayer.CreateField(oFieldName);
                } else {
                    FieldDefn oFieldName = new FieldDefn(key.toUpperCase(), ogr.OFTString);
                    oFieldName.SetWidth(300);
                    gdbLayer.CreateField(oFieldName);
                }
            }
        });
        return gdbLayer;
    }


    /***
     * gdal layer 转换为 feature
     * @param epscCode
     * @param geoJsonFeature
     * @param layer
     * @return
     */
    public static List<GeoFeature> layerFeatureToFeature(String epscCode, GeoJsonFeature geoJsonFeature, Layer layer)  {
        Feature feature;
        GeoCrs geoCrs = new GeoCrs();
        GeoCrsProperties geoCrsProperties = new GeoCrsProperties();
        geoCrsProperties.setName("EPSG:" + epscCode);
        geoCrs.setProperties(geoCrsProperties);
        geoJsonFeature.setCrs(geoCrs);
        FeatureDefn featureDefn = layer.GetLayerDefn();

        List<GeoFeature> features = new ArrayList<>();

        while ((feature = layer.GetNextFeature()) != null) {
            // 获取特征的几何信息

            GeoFeature simpleFeature = new GeoFeature();
            int fieldCount = feature.GetFieldCount();
            //属性
            JSONObject properties = new JSONObject();
            for (int item = 0; item < fieldCount; item++) {
                FieldDefn fieldDefn = featureDefn.GetFieldDefn(item);
                String fieldValue = feature.GetFieldAsString(item);
                properties.put(fieldDefn.GetName(), fieldValue);
            }
            //空间数据
            String json = feature.GetGeometryRef().ExportToJson();
            BaseGeometry geometry = JacksonUtil.toObject(json, BaseGeometry.class);
            simpleFeature.setGeometry(geometry);
            simpleFeature.setProperties(properties);
            //默认值
            simpleFeature.setType("Feature");

            features.add(simpleFeature);
            // 释放特征对象
            feature.delete();
        }
        return features;
    }


}
